use std::{io, time::Duration};
use windows::core::Error as WinError;

use crate::ipc;


#[derive(Clone, Copy, Debug, PartialEq)]
pub(super) enum BlockingMode {
    Blocking,
    Nonblocking,
    Timeout(Duration),
}


#[derive(Clone, Copy, Debug)]
pub(super) enum AtomicMode {
    Atomic,
    Nonatomic,
}



#[derive(Debug)]
pub enum WinIpcError {
    WinError(WinError),
    ChannelClosed,
    NoData,
}

impl WinIpcError {
    pub fn channel_is_closed(&self) -> bool {
        matches!(self, Self::ChannelClosed)
    }
}

impl From<WinIpcError> for bincode::Error {
    fn from(error: WinIpcError) -> bincode::Error {
        io::Error::from(error).into()
    }
}

impl From<WinError> for WinIpcError {
    fn from(e: WinError) -> Self {
        Self::WinError(e)
    }
}

impl From<WinIpcError> for ipc::IpcError {
    fn from(error: WinIpcError) -> Self {
        match error {
            WinIpcError::ChannelClosed => ipc::IpcError::Disconnected,
            e => ipc::IpcError::Io(io::Error::from(e)),
        }
    }
}

impl From<WinIpcError> for ipc::TryRecvError {
    fn from(error: WinIpcError) -> Self {
        match error {
            WinIpcError::ChannelClosed => ipc::TryRecvError::IpcError(ipc::IpcError::Disconnected),
            WinIpcError::NoData => ipc::TryRecvError::Empty,
            e => ipc::TryRecvError::IpcError(ipc::IpcError::Io(io::Error::from(e))),
        }
    }
}

impl From<WinIpcError> for io::Error {
    fn from(error: WinIpcError) -> io::Error {
        match error {
            WinIpcError::ChannelClosed => {
                // This is the error code we originally got from the Windows API
                // to signal the "channel closed" (no sender) condition --
                // so hand it back to the Windows API to create an appropriate `Error` value.
                io::Error::from_raw_os_error(windows::Win32::Foundation::ERROR_BROKEN_PIPE.0 as i32)
            },
            WinIpcError::NoData => io::Error::new(
                io::ErrorKind::WouldBlock,
                "Win channel has no data available",
            ),
            WinIpcError::WinError(err) => io::Error::from_raw_os_error(err.code().0),
        }
    }
}
